home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload Trio 2
/
Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO
/
dir24
/
psi110g.zip
/
TWIN_DR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-17
|
62KB
|
2,006 lines
/****************************************************************************
*
* COPYRIGHT 1990,91,92 BY GRACILIS INC.
*
* 623 Palace St.
* Aurora, Il. 60506
*
* GRACILIS, INC., MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS
* SOFTWARE FOR ANY PURPOSE.
*
* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
*
* Permission is granted for non-commercial distribution only.
*
******************************************************************************/
/****************************************************************************
*
*
* File: twin_dr.c
*
* Rev : 3.0
*
* Description:
*
* This File contains routines that implement PackeTwin
* synchronous SCC driver with an interface to KA9Q's TCP/IP suite.
*
*
* Routines:
*
* tsync_raw - Applications' routine for transmitting
* a message via tsync_driver.
*
* tsync_stop - Stop I/O
*
* tsync_recv - Applications' routine for receiving a message
* from the tsync_driver. Left over from NET.
*
*
* tsync_hwinit - Initialize the SCC chip for synchronous operation.
*
* tsync_txisr - Handles transmit interrupts.
*
* tsync_rxisr - Handles receive interrupts.
*
* tsync_xstatisr - Handles the SCC's external status interrupts.
*
* transon - Turn-on transmitter and turn-off receiver or
* turn-off transmitter and turn-on receiver.
* Will change txstate. Also
* handles time delays needed for data set
* control signals (RTS).
*
*/
#include <dos.h>
#include "global.h"
#ifdef PACKETWIN
#include "hardware.h"
#include "mbuf.h"
#include "iface.h"
#include "ax25.h"
#include "trace.h"
#include "proc.h"
#include "pktdrvr.h"
#include "z8530.h"
#include "gracilis.h"
#include "twin.h"
#ifdef TSYNC_DEBUG
unsigned char Lastint;
#endif
#ifdef SCOPE_LOOP
unsigned char scope_state = 0;
#endif
/* interrupt handler */
extern INTERRUPT twinvec();
INTERRUPT (*Twin_oldvec) __ARGS((void)); /* Old vector contents */
INTERRUPT (*Twin_handler) __ARGS((void)) = { twinvec };
unsigned int Twin_io_base = 0x230;
int16 Twin_vector;
int Twin_cputype;
/* The pwait/psignal inter-process communication wake-up array */
/* for getting pre-allocated receive buffers */
int Twin_bufpp[5];
/* The pwait/psignal inter-process communication wake-up array */
/* for kicking the transmitter */
int Twin_kickpp[5];
/* The pwait/psignal inter-process communication wake-up array */
/* for free-ing transmitted messages */
int Twin_freetxpp[5];
uchar Twin_sercfg = 0; /* image of the SERIAL_CFG port */
uchar Twin_dmacfg = 0; /* image of the DMA_CFG port */
/* Master device control blocks for the Tsync drivers... */
UNI_DCB Twin_udcb[2] = {
FALSE, 0, NULL, NULL, NULL, NULL, NULL,
FALSE, 0, NULL, NULL, NULL, NULL, NULL,
};
/* a simple delay instruction... */
int nop1;
#define nop nop1++;
void tsync_txisr(DCB *);
void tsync_entpt(void);
void empty_scc(int16,int16);
void tsync_srcisr(DCB *);
void time_wait(DCB *,struct drv_timer *,int16,void (*timerfunc)(),unsigned long);
void transon(DCB *,int16);
void tsync_persist(DCB *);
void tsync_sqdelay(DCB *);
void tsync_txondelay(DCB *);
/* Send raw packet */
int
tsync_raw(intfp, mbufp)
register struct iface *intfp;
register struct mbuf *mbufp;
{
register DCB *dcbp;
register struct drvbuf *xbufp ;
int16 msgsize;
int i_state;
#ifdef TSYNC_DEBUG_PRT
int16 pullsize;
#endif
#ifdef OLD_KA9Q
dump(intfp, IF_TRACE_OUT, CL_AX25, mbufp);
#else
dump(intfp,IF_TRACE_OUT,mbufp);
#endif
dcbp = (DCB *)Twin_udcb[intfp->dev].dcbp;
/* get packet's transmission size */
msgsize = len_p(mbufp);
xbufp = (struct drvbuf *)malloc(sizeof(struct drvbuf) + msgsize);
/* If no memory for buffering... then dump the packet on floor */
/* and return error to caller */
if(xbufp == (struct drvbuf *)NULL)
{
free_p(mbufp);
return(-1);
}
xbufp->msgsize = msgsize;
xbufp->next = (struct drvbuf *)NULLBUF;
#ifdef TSYNC_DEBUG_PRT
if ( (pullsize = dqdata(mbufp, &(xbufp->buf), msgsize+1)) != msgsize )
{ /* somethings wrong. should have gotten all of message */
printf("tsync_raw error wanted %d bytes pullup-up got only %d\n",
msgsize, pullsize);
}
#else
/* there will be no check for mismatching msgsize and pullsize */
dqdata(mbufp, &(xbufp->buf), msgsize);
#endif
/* now enqueue the message !!! */
i_state = dirps();
if ( dcbp->xmtq == (struct drvbuf *)NULLBUF )
{
dcbp->xmtq = dcbp->xmtqtail = xbufp;
}
else
{
dcbp->xmtqtail->next = xbufp;
dcbp->xmtqtail = xbufp;
}
/* Note tsync_txisr must be able to run from ISR level as well */
/* as from "task" level, since tsync_raw is called from task */
/* level */
/* Only if the transmitter is not doing anything then call it */
if ( dcbp->txstate == IDLE )tsync_txisr(dcbp);
restore(i_state);
return(0);
}
/*
* Master interrupt handler. One interrupt at a time is handled.
* here. Service routines are called from here.
*
* This 8530 interrupt handler will take care of both async and
* sync drivers' interrupts.
*/
/******************************************************/
/* 85230 Mods: */
/******************************************************/
/* NOTE: This interrupt handler is constructed to get */
/* around a bug in the Zilog 85c230 while */
/* still allowing use of it's advanced FIFOs */
/* */
/* The basic bug is as follows... */
/* If an interrupt driver is written for the */
/* 85230, which does NOT make use of the */
/* automatic vector generation facilities */
/* provided by RR2, AND..... */
/* If RR1 is used as the ONLY means of */
/* identifying the End of a received frame, */
/* then the 85230 will mis-report the EOF */
/* when the 1st byte of a CRC is read from */
/* the receive FIFO, resulting in checking */
/* the CRC status flag at the wrong time. */
/* This of course then indicates a CRC */
/* error, and results in the driver */
/* discarding an otherwise good frame... */
/* */
/* The FIX: */
/* The Basic idea here is to simulate the */
/* use of true VECTORED interrupts. */
/* */
/* First look for a pending interrupt in */
/* RR3, then read the VECTOR which would */
/* have been generated IF we were using */
/* vectored interrupts. Dispatch to the */
/* appropriate handler routine. */
/* */
/* The reason this approach works is that the */
/* Special Receive condition interrupt VECTOR */
/* is not asserted until AFTER the first CRC */
/* byte is read from the FIFO. This is the */
/* expected behaviour, and allows the programmer */
/* to read the second CRC byte, and know that */
/* he/she may appropriately check the CRC status */
/* indicator, for the completed frame. */
/* Additionally, it is known at this point that */
/* the last two bytes received are the CRC bytes */
/* which must be discarded, since they are not */
/* a part of the user data frame. */
/* */
/* MORAL: Dont believe RR1's end of received frame */
/* indication, until you have first waited */
/* for a SPECIAL RECEIVE CONDITION VECTOR */
/* to be asserted... or YOU'll be SORRY!!! */
/******************************************************/
void
tsync_entpt()
{
register char st;
#ifdef notdef
int i_state;
#endif
register DCB *dcbp;
register int16 ctl;
register unsigned intreg;
struct drv_timer *tblk;
void (*timer_func)(unsigned long);
#ifdef notdef
i_state = dirps();
#endif
intreg = inportb( Twin_io_base + INT_REG);
while((intreg & (0x07)) != 0x07 )
{
/* Read interrupt pending register from channel A */
while(Twin_read_scc( Twin_io_base+SCCA_CMD,R3) != 0 )
{
/* Get interrupt vector info from Channel B RR2 */
st = (Twin_read_scc( Twin_io_base+SCCB_CMD,R2) & 0x0E);
#ifdef TSYNC_DEBUG
Lastint = st;
#endif
switch(st)
{
case VEC_CHB_TBE:
/* Channel B Transmit Int Pending */
dcbp = (DCB *)Twin_udcb[TWINCOMM2].dcbp;
/* milt tsync_txisr(dcbp); */
/* Call the Transmit Buffer Empty Handler */
(*(Twin_udcb[TWINCOMM2].prev_vec2))(dcbp);
ctl = (int16)(Twin_io_base+SCCB_CMD);
break;
case VEC_CHB_XTS:
/* Channel B External Status Int */
dcbp = (DCB *)Twin_udcb[TWINCOMM2].dcbp;
/* milt tsync_xstatisr(dcbp); */
/* Call the External Status Change Handler */
(*(Twin_udcb[TWINCOMM2].prev_vec4))(dcbp);
ctl = (int16)(Twin_io_base+SCCB_CMD);
break;
case VEC_CHB_RCAV:
/* Channel B Rcv Interrupt Pending */
dcbp = (DCB *)Twin_udcb[TWINCOMM2].dcbp;
/* milt tsync_rxisr(dcbp); */
/* Call the Receive Character Available Handler */
(*(Twin_udcb[TWINCOMM2].prev_vec3))(dcbp);
ctl = (int16)(Twin_io_base+SCCB_CMD);
break;
case VEC_CHB_SRC:
/* Channel B Special Rcv Int Pending */
dcbp = (DCB *)Twin_udcb[TWINCOMM2].dcbp;
/* milt tsync_rxisr(dcbp); */
/* Call the Special Receive Condition Handler */
(*(Twin_udcb[TWINCOMM2].prev_vec3))(dcbp);
ctl = (int16)(Twin_io_base+SCCB_CMD);
break;
case VEC_CHA_TBE:
/* Channel A Transmit Int Pending */
dcbp = (DCB *)Twin_udcb[TWINCOMM1].dcbp;
/* milt tsync_txisr(dcbp); */
/* Call the Transmit Buffer Empty Handler */
(*(Twin_udcb[TWINCOMM1].prev_vec2))(dcbp);
ctl = (int16)(Twin_io_base+SCCA_CMD);
break;
case VEC_CHA_XTS:
/* Channel A External Status Int */
dcbp = (DCB *)Twin_udcb[TWINCOMM1].dcbp;
/* milt tsync_xstatisr(dcbp); */
/* Call the External Status Change Handler */
(*(Twin_udcb[TWINCOMM1].prev_vec4))(dcbp);
ctl = (int16)(Twin_io_base+SCCA_CMD);
break;
case VEC_CHA_RCAV:
/* Channel A Rcv Interrupt Pending */
dcbp = (DCB *)Twin_udcb[TWINCOMM1].dcbp;
/* milt tsync_rxisr(dcbp); */
/* Call the Receive Character Available Handler */
(*(Twin_udcb[TWINCOMM1].prev_vec3))(dcbp);
ctl = (int16)(Twin_io_base+SCCA_CMD);
break;
case VEC_CHA_SRC:
/* Channel A Special Rcv Int Pending */
dcbp = (DCB *)Twin_udcb[TWINCOMM1].dcbp;
/* milt tsync_rxisr(dcbp); */
/* Call the Special Receive Condition Handler */
(*(Twin_udcb[TWINCOMM1].prev_vec3))(dcbp);
ctl = (int16)(Twin_io_base+SCCA_CMD);
break;
}
/* Reset highest interrupt under service */
#ifdef TSYNC_DEBUG
Twin_write_scc(ctl,R0,(dcbp->wr0 = RES_H_IUS));
#else
Twin_write_scc(ctl,R0,RES_H_IUS);
#endif
}
if(!(intreg & PKTWIN_TMR1_MSK))
{
dcbp = (DCB *)Twin_udcb[TWINCOMM1].dcbp;
tblk = dcbp->timer1;
/* Now clear the timer interrupt */
inportb(Twin_io_base + CLR_TMR1);
/* Now perform the timer's requested function */
if(tblk->thandler != NULL)
{
timer_func = tblk->thandler;
tblk->thandler = (void (*)())NULL;
(timer_func)(tblk->targ);
}
}
if(!(intreg & PKTWIN_TMR2_MSK))
{
dcbp = (DCB *)Twin_udcb[TWINCOMM2].dcbp;
tblk = dcbp->timer1;
/* Now clear the timer interrupt */
inportb(Twin_io_base + CLR_TMR2);
/* Now perform the timer's requested function */
if(tblk->thandler != NULL)
{
timer_func = tblk->thandler;
tblk->thandler = (void (*)())NULL;
(timer_func)(tblk->targ);
}
}
intreg = inportb( Twin_io_base + INT_REG);
}
#ifdef notdef
/* Dont need this... causewe only got here though an int... */
restore(i_state);
#endif
}
/*
* External/Status interrupts caused by a receiver abort,
* a Transmit UNDERRUN/EOM.
* SCC enters hunt mode on an abort.
*
* On a Transmit Underrun, change state and
* issue a reset command for it, and return.
*/
void
tsync_xstatisr(dcbp)
register DCB *dcbp;
{
register uchar scc_stat,newstat,new_xbits;
/* find out why the external/status interrupt occurred */
scc_stat = Twin_read_scc(dcbp->zhwmap.ctl,R0);
/* 9/23/91 DGL Try to fix possible race condition */
/* reset external status latch to enable future changes to catch us */
#ifdef TSYNC_DEBUG
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = RES_EXT_INT));
#else
Twin_write_scc(dcbp->zhwmap.ctl,R0,RES_EXT_INT);
#endif
new_xbits = scc_stat ^ dcbp->extreg;
/* Check for Tx UNDERRUN/EOM */
if(new_xbits & TxEOM )
{
if(dcbp->dma_flg == TRUE)
{
/* Disable this DMA channel */
outportb(DMAWSMR,dcbp->dma_tx_chan | 0x04);
dcbp->txstate = TX_DONE;
/* update the xmit data tally*/
dcbp->txbytecnt += dcbp->cur_xbytes;
/* don't allow Underruns to interrupt us */
Twin_write_scc(dcbp->zhwmap.ctl,R15,(dcbp->wr15 &= ~0x40));
/* set the TxEOM bit in the image */
dcbp->extreg |= TxEOM;
/* enable the tx empty interrupt... */
/* so it can catch us if necessary */
/* This handles condition where the buffer */
/* goes empty while we're checking... */
/* Avoid's a race. 9/23/91 */
#ifdef TSYNC_DEBUG
Twin_write_scc(dcbp->zhwmap.ctl,R1,(dcbp->wr1 = 0xfb));
#else
Twin_write_scc(dcbp->zhwmap.ctl,R1,0xfb);
#endif
/* Now check to see if the CRC has already cleared */
/* the SCC's xmit buffer... */
newstat = Twin_read_scc(dcbp->zhwmap.ctl,R0);
/* If so, turn off the tx empty interrupt we just enabled */
/* and process the end of frame condition */
if(newstat & Tx_BUF_EMP)
{
/* Rx and Extern ints on : No Tx ints */
#ifdef TSYNC_DEBUG
Twin_write_scc(dcbp->zhwmap.ctl,R1,(dcbp->wr1 = 0xf9));
#else
Twin_write_scc(dcbp->zhwmap.ctl,R1,0xf9);
#endif
tsync_txisr(dcbp);
}
/* else... it will happen under interrupt ctl */
/* when the buffer goes empty */
}
else
{
/* set the TxEOM bit in the image */
dcbp->extreg |= TxEOM;
if((dcbp->txstate == TX_ACTIVE) || (dcbp->txstate == CRCING))
{
dcbp->txstate = TX_DONE;
/* don't allow Underruns to interrupt us */
Twin_write_scc(dcbp->zhwmap.ctl,R15,(dcbp->wr15 &= ~0x40));
/* if unexpected... bump transmit underrun counts */
if( dcbp->cur_xbytes > 0 )
{
dcbp->txunderun++;
}
/* enable the tx empty interrupt... */
/* so it can catch us if necessary */
/* This handles condition where the buffer */
/* goes empty while we're checking... */
/* Avoid's a race. 9/23/91 */
#ifdef TSYNC_DEBUG
Twin_write_scc(dcbp->zhwmap.ctl,R1,(dcbp->wr1 = 0x13));
#else
Twin_write_scc(dcbp->zhwmap.ctl,R1,0x13);
#endif
/* check to see if the CRC has already cleared */
/* the SCC's xmit buffer... */
newstat = Twin_read_scc(dcbp->zhwmap.ctl,R0);
/* If so, turn off the tx empty interrupt we just enabled */
/* and process the end of frame condition */
if(newstat & Tx_BUF_EMP)
{
#ifdef TSYNC_DEBUG
Twin_write_scc(dcbp->zhwmap.ctl,R1,(dcbp->wr1 = 0x11));
#else
Twin_write_scc(dcbp->zhwmap.ctl,R1,0x11);
#endif
tsync_txisr(dcbp);
}
/* else... it will happen under interrupt ctl */
}
}
}
/* Receive Mode only
* This triggers when hunt mode is entered, & since an ABORT
* automatically enters hunt mode, we use that to clean up
* any waiting garbage
*/
if(new_xbits & BRK_ABRT )
{
if(scc_stat & BRK_ABRT ) dcbp->extreg |= BRK_ABRT;
else dcbp->extreg &= ~BRK_ABRT;
dcbp->rxstate = RXABORT;
dcbp->rxabortcnt++; /* bump aborts */
/* No more Abort interrupts */
#ifdef notdef
Twin_write_scc(dcbp->zhwmap.ctl,R15,(dcbp->wr15 &= ~(0x80)));
#endif
if(dcbp->dma_flg == TRUE)
{
rxprime_dma(dcbp); /* restart for a new frame */
}
else
{
/* reset err latch */
#ifdef TSYNC_DEBUG
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = ERR_RES));
#else
Twin_write_scc(dcbp->zhwmap.ctl,R0,ERR_RES);
#endif
/* read and toss any data */
inportb(dcbp->zhwmap.data);
inportb(dcbp->zhwmap.data);
inportb(dcbp->zhwmap.data);
inportb(dcbp->zhwmap.data);
/* make sure dcbp->rxbufp has a data buffer to work with!!! */
dcbp->rxcurp = dcbp->rxbufp->data;
#ifdef OLD_KA9Q
dcbp->rxbufp->cnt = sizeof(struct phdr);
#else
dcbp->rxbufp->cnt = 0;
#endif
/* resync the receiver... */
#ifdef TSYNC_DEBUG
Twin_write_scc(dcbp->zhwmap.ctl,R3,(dcbp->wr3 = 0xf9));
#else
Twin_write_scc(dcbp->zhwmap.ctl,R3,0xf9);
#endif
}
}
if(new_xbits & DCD )
{
if((scc_stat & DCD) == 0)
{
dcbp->extreg &= ~DCD;
if(dcbp->dma_flg == TRUE)
{
rxprime_dma(dcbp); /* restart for a new frame */
}
else
{
/* reset err latch */
#ifdef TSYNC_DEBUG
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0=ERR_RES));
#else
Twin_write_scc(dcbp->zhwmap.ctl,R0,ERR_RES);
#endif
/* read and toss any data */
inportb(dcbp->zhwmap.data);
inportb(dcbp->zhwmap.data);
inportb(dcbp->zhwmap.data);
inportb(dcbp->zhwmap.data);
/* make sure dcbp->rxbufp has a data buffer to work with!!! */
dcbp->rxcurp = dcbp->rxbufp->data;
#ifdef OLD_KA9Q
dcbp->rxbufp->cnt = sizeof(struct phdr);
#else
dcbp->rxbufp->cnt = 0;
#endif
/* resync the receiver... */
/* Rx 8 bit/chars, enter hunt mode, CRC enable */
#ifdef TSYNC_DEBUG
Twin_write_scc(dcbp->zhwmap.ctl,R3,(dcbp->wr3 = 0xf9));
#else
Twin_write_scc(dcbp->zhwmap.ctl,R3,0xf9);
#endif
}
}
else dcbp->extreg |= DCD;
}
if(new_xbits & CTS )
{
if((scc_stat & CTS) == 0)
{
dcbp->extreg &= ~CTS;
dcbp->txctslost++;
if((dcbp->txstate == TX_ACTIVE) || (dcbp->txstate == CRCING))
{
dcbp->txstate = TX_DONE;
/* don't allow Underruns to interrupt us */
Twin_write_scc(dcbp->zhwmap.ctl,R15,(dcbp->wr15 &= ~0x40));
/* if unexpected... bump transmit underrun counts */
if( dcbp->cur_xbytes > 0 )
{
dcbp->txunderun++;
}
/* Toss the frame being sent, and continue... */
tsync_txisr(dcbp);
}
}
else dcbp->extreg |= CTS;
}
#ifdef notdef /* fix race 9/23/91 */
/* reset external status latch */
#ifdef TSYNC_DEBUG
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = RES_EXT_INT));
#else
Twin_write_scc(dcbp->zhwmap.ctl,R0,RES_EXT_INT);
#endif
#endif
return;
}
/*
* end of tsync_xstatisr
******************************************************************/
/*
* Receive ISR.
* The first receive buffer is pre-allocated
* in the init routine. Thereafter, it is filled here, queued out, and a
* new one acquired. CRC, OVERRUN and TOOBIG errors merely 'rewind' the
* pointers and reuse the same buffer.
*/
void
tsync_rxisr(dcbp)
register DCB *dcbp;
{
register int16 ctl;
int16 data;
struct mbuf *f_dequeavail();
unsigned char vecmsk;
/* If this channel is a DMA channel handle it elsewhere */
if(dcbp->dma_flg == TRUE)
{
tsync_rxdmaisr(dcbp);
return;
}
/* speed up access to 8530 regs */
ctl = dcbp->zhwmap.ctl;
data = dcbp->zhwmap.data;
/* Get interrupt vector info from Channel B RR2 */
vecmsk = (Twin_read_scc( Twin_io_base+SCCB_CMD,R2) & 0x0E);
/* If this is an SRC interrupt... handle it that way... */
if((vecmsk == VEC_CHA_SRC) || (vecmsk == VEC_CHB_SRC))
{
tsync_srcisr(dcbp);
return;
}
/* Check status of receive interrupt */
if(Twin_read_scc(ctl,R0) & Rx_CH_AV)
{
/* get char and store it */
*dcbp->rxcurp++ = inportb(data);
/* tally data byte received */
dcbp->rxbytecnt++;
/* Allow aborts to get us after we receive a first char */
#ifdef OLD_KA9Q
if(dcbp->rxbufp->cnt == sizeof(struct phdr))
#else
if(dcbp->rxbufp->cnt == 0)
#endif
{
/* allow Aborts to interrupt us. */
Twin_write_scc(ctl,R15,(dcbp->wr15 |= 0x80));
}
/* bump count & check for TOOBIG frames... */
#ifdef OLD_KA9Q
if ((++dcbp->rxbufp->cnt) >= (dcbp->rxbufsize+sizeof(struct phdr)))
#else
if ((++dcbp->rxbufp->cnt) >= dcbp->rxbufsize)
#endif
{
/* dump buffer - incoming packet is too big */
dcbp->rxtruncnt++;
/* read all the data out of the rx fifo... */
/* and TOSS it.. */
empty_scc(ctl,data);
/* reset buf "pointers" - dump data */
dcbp->rxcurp = dcbp->rxbufp->data;
#ifdef OLD_KA9Q
dcbp->rxbufp->cnt = sizeof(struct phdr);
#else
dcbp->rxbufp->cnt = 0;
#endif
/* restart the receiver in HUNT MODE... */
/* to resync it... */
#ifdef TSYNC_DEBUG
Twin_write_scc(dcbp->zhwmap.ctl,R3,(dcbp->wr3 = 0xf9));
#else
Twin_write_scc(dcbp->zhwmap.ctl,R3,0xf9);
#endif
}
}
return;
}
/*
* end of tsync_rxisr
****************************************************************/
/****************************************************************/
/* Special Receive Condition Interrupt Handler... */
/****************************************************************/
void
tsync_srcisr(dcbp)
register DCB *dcbp;
{
unsigned char rx1stat;
struct mbuf *tmpbufp;
struct mbuf *f_dequeavail();
register int16 ctl;
int16 data;
/* speed up access to 8530 regs */
ctl = dcbp->zhwmap.ctl;
data = dcbp->zhwmap.data;
/* Per ZILOG... only read R1 when R0 says there is */
/* a char waiting... */
/* get status byte from R1 */
if(Twin_read_scc(ctl,R0) & Rx_CH_AV)
{
rx1stat = Twin_read_scc(ctl,R1);
/* empty the 2nd CRC char */
inportb(data);
/* The End of Frame bit is ALWAYS associated with a character,
* usually, it is the last CRC char. Only when EOF is true can
* we look at the CRC byte to see if we have a valid frame
*/
dcbp->rxpackcnt++;
/* No Abort interrupts */
Twin_write_scc(ctl,R15,(dcbp->wr15 &= ~(0x80)));
/* END OF FRAME -- Make sure Rx was active */
if(rx1stat & END_FR)
{
/* got a packet - check for CRC error */
if ( (rx1stat & CRC_ERR) ||
#ifdef OLD_KA9Q
(dcbp->rxbufp->cnt < (sizeof(struct phdr) + 10)) )
#else
(dcbp->rxbufp->cnt < 10 ) )
#endif
{
/* error occurred; toss frame */
if (( rx1stat & CRC_ERR ) &&
#ifdef OLD_KA9Q
(dcbp->rxbufp->cnt >= (sizeof(struct phdr) + 10)))
#else
(dcbp->rxbufp->cnt >= 10) )
#endif
dcbp->rxcrcerrcnt++; /* bump CRC errs */
/* read all data out of the rx fifo...*/
/* and TOSS it.. */
empty_scc(ctl,data);
/* reusing the old data buffer "dumps" the data */
/* restart the receiver in HUNT MODE... */
/* to resync it... */
#ifdef TSYNC_DEBUG
Twin_write_scc(dcbp->zhwmap.ctl,R3,(dcbp->wr3 = 0xf9));
#else
Twin_write_scc(dcbp->zhwmap.ctl,R3,0xf9);
#endif
}
else
{
/* Got a valid packet !! */
/* get next buffer */
tmpbufp = f_dequeavail((struct mbuf **)&dcbp->rxavailq, (int16 *)&dcbp->rxavailcount);
if ( tmpbufp != NULLBUF )
{
/* dump crc bytes, i.e. '-1' */
dcbp->rxbufp->cnt -= 1;
/* new for NOS */
/* adjust for packet header */
#ifdef OLD_KA9Q
dcbp->rxbufp->data -= sizeof(struct phdr);
enqueue(&Hopper, dcbp->rxbufp);
#else
net_route(dcbp->iface,dcbp->rxbufp);
#endif
/* bump packets rreceived */
/* successfully */
dcbp->rxnqued++;
dcbp->rxbufp = tmpbufp;
}
/* No buffers available... */
/* re-use old buffer - dump data */
else dcbp->nobufs++;
/* signal the process which */
/* allocates the rx buffers */
psignal(&Twin_bufpp[dcbp->dev],1);
} /* end good packet > 10 long received */
} /* End of FRAME */
/* Not EOF... check for overrun */
else if (rx1stat & Rx_OVR)
{
/* Rx overrun - toss buffer */
/* reset buffer pointers */
dcbp->rxovercnt++; /* bump overruns */
/* read all data out of the rx fifo...*/
/* and TOSS it.. */
empty_scc(ctl,data);
/* reuse old rx buffer.. */
/* restart the receiver in HUNT MODE... */
/* to resync it... */
#ifdef TSYNC_DEBUG
Twin_write_scc(dcbp->zhwmap.ctl,R3,(dcbp->wr3 = 0xf9));
#else
Twin_write_scc(dcbp->zhwmap.ctl,R3,0xf9);
#endif
}
/* regardless of why we terminating/restarting... */
/* make sure dcbp->rxbufp has a data buffer!!! */
dcbp->rxcurp = dcbp->rxbufp->data;
#ifdef OLD_KA9Q
dcbp->rxbufp->cnt = sizeof(struct phdr);
#else
dcbp->rxbufp->cnt = 0;
#endif
/* reset err latch */
#ifdef TSYNC_DEBUG
Twin_write_scc(ctl,R0,(dcbp->wr0 = ERR_RES));
#else
Twin_write_scc(ctl,R0,ERR_RES);
#endif
}
}
/* read the SCC channel till no more data in receiver... */
void
empty_scc(ctl,data)
int16 ctl,data;
{
while(Twin_read_scc(ctl,R0) & Rx_CH_AV)
{
/* get char and toss it */
inportb(data);
}
}
/*
* DMA Receive ISR.
* The first receive buffer is pre-allocated
* in the init routine. Thereafter, it is filled here, queued out, and a
* new one acquired. CRC, OVERRUN and TOOBIG errors merely 'rewind' the
* pointers and reuse the same buffer.
*/
tsync_rxdmaisr(dcbp)
register DCB *dcbp;
{
register int16 ctl;
register int16 dmacnt;
char rxstat;
int16 rxbytecnt;
struct mbuf *f_dequeavail();
struct mbuf *tmpbufp;
/* mask off this DMA channel */
outportb(DMAWSMR,(dcbp->dma_rx_chan | 0x04));
/* speed up access to 8530 regs */
ctl = dcbp->zhwmap.ctl;
/* Check status of receive interrupt */
rxstat = Twin_read_scc(ctl,R1); /* get status byte from R1 */
/* clear the DMA byte ptr FF */
outportb(DMAFFCL,00);
/* Rx overrun - toss data by reusing the buffer */
if (rxstat & Rx_OVR ) dcbp->rxovercnt++; /* bump overruns */
/* The End of Frame bit is ALWAYS associated with a character,
* usually, it is the last CRC char. Only when EOF is true can
* we look at the CRC byte to see if we have a valid frame
*/
/* CRC error occurred; toss frame */
else if ((rxstat & (CRC_ERR|END_FR)) == (CRC_ERR|END_FR) )
{
dcbp->rxpackcnt++;
dcbp->rxcrcerrcnt++;
}
else if( rxstat & END_FR )
{
/* Disable further Abort interrupts */
Twin_write_scc(ctl,R15,(dcbp->wr15 &= ~(0x80)));
dcbp->rxpackcnt++;
/* calculate # of bytes received less CRC */
dmacnt = inportb(dcbp->dma_rx_cnt_reg);
dmacnt += (inportb(dcbp->dma_rx_cnt_reg) << 8);
rxbytecnt = (dcbp->rxbufsize-1) - dmacnt;
dcbp->rxbufp->cnt += rxbytecnt;
/* # of data bytes received... Not including CRC's */
dcbp->rxbytecnt += rxbytecnt-2;
/* Make sure Rx was active */
#ifdef OLD_KA9Q
if ( dcbp->rxbufp->cnt > sizeof(struct phdr) )
#else
if ( dcbp->rxbufp->cnt > 0)
#endif
{ /* then bytes have been received */
#ifdef OLD_KA9Q
if ( dcbp->rxbufp->cnt >= (sizeof(struct phdr)+10) )
#else
if ( dcbp->rxbufp->cnt >= 10 )
#endif
{
/* Got a valid packet !! */
/* get next buffer */
tmpbufp = f_dequeavail((struct mbuf **)&dcbp->rxavailq, (int16 *)&dcbp->rxavailcount);
if ( tmpbufp != NULLBUF )
{
/* dump crc bytes, i.e. '-2' */
dcbp->rxbufp->cnt -= 2;
/* new for NOS */
/* adjust for packet header */
#ifdef OLD_KA9Q
dcbp->rxbufp->data -= sizeof(struct phdr);
enqueue(&Hopper, dcbp->rxbufp);
#else
net_route(dcbp->iface,dcbp->rxbufp);
#endif
/* bump packets rreceived */
/* successfully */
dcbp->rxnqued++;
dcbp->rxbufp = tmpbufp;
}
/* No buffers available... */
/* re-use old buffer - dump data */
else dcbp->nobufs++;
/* signal the process which */
/* allocates the rx buffers */
psignal(&Twin_bufpp[dcbp->dev],1);
} /* end good packet > 10 long received */
} /* received frame with > 0 chars */
} /* end END_FR check */
rxprime_dma(dcbp);
return;
}
/*
* end of tsync_rxdmaisr
****************************************************************/
void
rxprime_dma(dcbp)
register DCB *dcbp;
{
register int16 ctl;
ulong realaddr;
unsigned page;
/* speed up access to 8530 regs */
ctl = dcbp->zhwmap.ctl;
/* make sure dcbp->rxbufp has data!!! */
dcbp->rxcurp = dcbp->rxbufp->data;
#ifdef OLD_KA9Q
dcbp->rxbufp->cnt = sizeof(struct phdr);
#else
dcbp->rxbufp->cnt = 0;
#endif
/* reset any errors... */
#ifdef TSYNC_DEBUG
Twin_write_scc(ctl,R0,(dcbp->wr0 = ERR_RES));
#else
Twin_write_scc(ctl,R0,ERR_RES);
#endif
/* Reprime the dma pump... */
/* A rendition of an absolute address for the ptr */
realaddr = ((ulong)FP_SEG(dcbp->rxcurp) << 4) +
(ulong)FP_OFF(dcbp->rxcurp);
/* DMA page reg for 8237 */
page = (unsigned)(realaddr >> 16);
outportb(dcbp->dma_rx_pagereg,page); /* setup 64k page */
/* mode setup required if we are in HDX operation */
if(dcbp->hduplex == TRUE)
{
outportb(DMAMODE,dcbp->dma_rx_chan | RX_DMA);
outportb(Twin_io_base+DMA_CFG,dcbp->dma_rx_mode);
}
/* clear the DMA byte ptr FF */
outportb(DMAFFCL,00);
/* Max xfer count setup */
outportb(dcbp->dma_rx_cnt_reg,dcbp->rxbufsize-1);
outportb(dcbp->dma_rx_cnt_reg,((dcbp->rxbufsize-1)>>8));
/* destination buffer address */
outportb(dcbp->dma_rx_addr_reg,(realaddr & 0xff));
outportb(dcbp->dma_rx_addr_reg,((realaddr >> 8) & 0xff));
/* If we are in DMA mode/Half duplex: Turn on the recvr */
/* Rx 8 bit/chars, enter hunt mode, CRC enable */
/* Autoenables... */
if(dcbp->hduplex == TRUE)
#ifdef TSYNC_DEBUG
Twin_write_scc(dcbp->zhwmap.ctl,R3,(dcbp->wr3 = 0xf9));
#else
Twin_write_scc(dcbp->zhwmap.ctl,R3,0xf9);
#endif
/* Enable this DMA channel */
outportb(DMAWSMR,dcbp->dma_rx_chan);
return;
}
/*
* PackTen's SCC transmit interrupt service routine
*/
void
tsync_txisr(dcbp)
register DCB *dcbp;
{
register int16 ctl;
register struct drvbuf *btemp;
int i_state;
#ifdef TSYNC_DEBUG
int tstbyt_cnt= 0;
#endif
/* This routine MAY be able to run with ints ENABLED later... */
/* We need to investigate... milt / {dgl} */
/* NEVER NEVER NEVER!!!!!!!!! */
i_state = dirps();
/* speedup access to 8530 regs */
ctl = dcbp->zhwmap.ctl;
switch (dcbp->txstate) {
case TX_ACTIVE:
/* Here we are actively sending a frame */
/* We should only hit this case in NON-DMA modes */
/* If there are more bytes to send... */
if( dcbp->cur_xbytes > 0 )
{
/* Try to feed the ESCC/SCC as many bytes as we can */
while((Twin_read_scc(ctl,R0) & Tx_BUF_EMP) && (dcbp->cur_xbytes > 0))
{
/* send next char and bump the pointer */
outportb(dcbp->zhwmap.data,*dcbp->cur_xbufp++);
/* tally data byte sent */
dcbp->txbytecnt++;
dcbp->cur_xbytes--;
#ifdef TSYNC_DEBUG
tstbyt_cnt++;
#endif
}
#ifdef TSYNC_DEBUG
if(tstbyt_cnt > dcbp->maxtxbytes)dcbp->maxtxbytes = tstbyt_cnt;
#endif
if(dcbp->cur_xbytes <= 0)
{
/* turn-off the xmission of Abort on underrun */
/* To allow the CRC to go out */
#ifdef TSYNC_DEBUG
if(dcbp->nrzi_flg == TRUE)
Twin_write_scc(ctl,R10,(dcbp->wr10 = 0xa0));
else Twin_write_scc(ctl,R10,(dcbp->wr10 = 0x80));
#else
if(dcbp->nrzi_flg == TRUE)
Twin_write_scc(ctl,R10,0xa0);
else Twin_write_scc(ctl,R10,0x80);
#endif
/* Sent all the data bytes, now send CRCs */
/* CRCING is a tsync_xstatisr state */
/* dcbp->txstate = CRCING;
*/
}
}
#ifdef notdef
if( dcbp->cur_xbytes > 0 )
{
/* send next char and bump the pointer */
outportb(dcbp->zhwmap.data,*dcbp->cur_xbufp++);
/* tally data byte sent */
dcbp->txbytecnt++;
/* sent a byte */
if((--dcbp->cur_xbytes) <= 0)
{
/* turn-off the xmission of Abort on underrun */
/* To allow the CRC to go out */
#ifdef TSYNC_DEBUG
if(dcbp->nrzi_flg == TRUE)
Twin_write_scc(ctl,R10,(dcbp->wr10 = 0xa0));
else Twin_write_scc(ctl,R10,(dcbp->wr10 = 0x80));
#else
if(dcbp->nrzi_flg == TRUE)
Twin_write_scc(ctl,R10,0xa0);
else Twin_write_scc(ctl,R10,0x80);
#endif
/* Sent all the data bytes, now send CRCs */
/* CRCING is a tsync_xstatisr state */
/* dcbp->txstate = CRCING;
*/
/* for slow PCs... */
}
}
#endif
else
{
#ifdef TSYNC_DEBUG
/* reset Tx int pending to allow the */
/* Underrun/EOM to happen */
Twin_write_scc(ctl,R0,(dcbp->wr0 = 0x28));
/* disable tx ints... */
Twin_write_scc(ctl,R1,(dcbp->wr1 = 0x11));
#else
/* reset Tx int pending to allow the */
/* Underrun/EOM to happen */
Twin_write_scc(ctl,R0,0x28);
/* disable tx ints... */
Twin_write_scc(ctl,R1,0x11);
#endif
/* Sent all the data bytes, now send CRCs */
/* CRCING is a tsync_xstatisr state */
dcbp->txstate = CRCING;
}
break;
case CRCING:
/* reset Tx int pending to allow the */
/* Underrun/EOM to happen */
#ifdef TSYNC_DEBUG
Twin_write_scc(ctl,R0,(dcbp->wr0 = 0x28));
#else
Twin_write_scc(ctl,R0,0x28);
#endif
break;
case TX_DONE: /* All done sending a packet... */
tsync_txdone:
/* for slow PCs... reenable the timer ints... */
if ((Twin_cputype < 2) && (dcbp->baud >= 9600L)) maskon(0);
/* sent a packet */
dcbp->txpackcnt++;
/* reset Tx int pending */
#ifdef TSYNC_DEBUG
Twin_write_scc(ctl,R0,(dcbp->wr0 = 0x28));
#else
Twin_write_scc(ctl,R0,0x28);
#endif
/* If we were not called by mistake... */
/* I.E. by an underrun with no current buffer... */
if(dcbp->xmtq != (struct drvbuf *)NULLBUF)
{
/* done sending message so move on to next one */
if ( dcbp->freem == (struct drvbuf *)NULLBUF )
{
dcbp->freem = dcbp->xmtq;
dcbp->xmtq = dcbp->xmtq->next;
dcbp->freem->next = (struct drvbuf *)NULLBUF;
}
else
{
btemp = dcbp->xmtq; /* addr of one to free */
dcbp->xmtq = btemp->next; /* next one TO BE xmitted */
btemp->next = dcbp->freem; /* one to be freed is queued */
dcbp->freem = btemp; /* now set free head ptr */
}
/* signal the process which is supposed to free the */
/* transmitted message */
psignal(&Twin_freetxpp[dcbp->dev],1);
}
/* Check NEW xmtq */
if(dcbp->xmtq == (struct drvbuf *)NULLBUF)
{
/* no more msgs to send */
dcbp->xmtqtail = (struct drvbuf *)NULLBUF;
/* take care of SQUELCH DELAY wait for */
/* flag byte to go out */
dcbp->txstate = TX_KEYDOWN_DELAY;
#ifdef notdef
/* shouldn't need this... if we reset the tx ip bit */
/* Turn off Tx ints */
if(dcbp->dma_flg == FALSE)Twin_write_scc(ctl,R1,(dcbp->wr1 = 0x11));
else Twin_write_scc(ctl,R1,(dcbp->wr1 = 0xf9));
#endif
transon(dcbp,OFF);
}
else
{
/* immediately start sending the next msg */
dcbp->cur_xbufp = &(dcbp->xmtq->buf);
dcbp->cur_xbytes = dcbp->xmtq->msgsize;
txprime_dma(dcbp); /* start sending a frame */
}
break;
case IDLE: /* Transmitter idle. Find a frame for transmission */
if ( dcbp->xmtq == (struct drvbuf *)NULLBUF )
{
/* totally idle dudes */
/* reset Tx int pending */
#ifdef TSYNC_DEBUG
Twin_write_scc(ctl,R0,(dcbp->wr0 = 0x28));
#else
Twin_write_scc(ctl,R0,0x28);
#endif
break;
}
else
{
/* point to the next message to send */
dcbp->cur_xbufp = &(dcbp->xmtq->buf);
dcbp->cur_xbytes = dcbp->xmtq->msgsize;
dcbp->txstate = DEFER; /* AND FALL THROUGH */
}
case DEFER:
/* If we are in HALF-DUPLEX mode, then we must wait */
/* for a free channel, and be polite about it (ppersist) */
/* Otherwise just fire up the transmitter... */
if(dcbp->hduplex == TRUE)
{
/* Check DCD so we don't step on a frame being received */
/* DCD is ACTIVE LOW on the SCC DCD pin, but the bit in R0 */
/* is SET when DCD is ACTIVE!! */
#ifdef notdef
/* This was the way it was released originally... */
/* I changed it cause I think this is more robust, if we somehow dropped */
/* an external status event.... We now poll the CD line to determine if */
/* we can send, and if needed, then we also will re_sync the extrn stats reg */
if(dcbp->extreg & DCD)
#endif
if ( (Twin_read_scc(dcbp->zhwmap.ctl,R0) & DCD) != 0 )
{
/* DGL 9/22/91 */
/* sync_up the extreg, if it somehow gets out of sync */
if(!(dcbp->extreg & DCD)) dcbp->extreg |= DCD;
#ifdef TSYNC_DEBUG_PRT
printf("TSYNC_TXISR: Device num %d DEFER state DCD is not right to xmit \n", dcbp->dev);
#endif
psignal(&Twin_kickpp[dcbp->dev],1);
break;
}
/* DCD is down */
if ( (dcbp->ioctlparams->persist & 0x00ff) <= (rand() & 0x00ff) )
{ /* then have to wait, be a less persistent */
dcbp->txstate = TX_PERSIST;
time_wait(dcbp,dcbp->timer1, dcbp->ioctlparams->slotime, tsync_persist,(long)dcbp);
break;
}
} /* end of Half duplex carrier handling... */
/* Raise RTS and start transmiting */
/* txstate is changed by the routine, but when */
/* tsync_txisr is called next the state will be KEYED_UP */
dcbp->txstate = TX_KEYUP_DELAY;
transon(dcbp,ON);
break;
case KEYED_UP:
/* RTS is ACTIVE or in radio terms the radio is keyed */
/* and transmiting */
txprime_dma(dcbp); /* start sending a frame */
/* chars will be going out */
break;
default:
#ifdef TSYNC_DEBUG_PRT
printf("DEBUG tsync_txisr: invalid txstate, %d \n\r", dcbp->txstate);
#endif
/* reset Tx int pending */
#ifdef TSYNC_DEBUG
Twin_write_scc(ctl,R0,(dcbp->wr0 = 0x28));
#else
Twin_write_scc(ctl,R0,0x28);
#endif
break;
/* end switch */
}
restore(i_state);
return;
}
void
txprime_dma(dcbp)
register DCB *dcbp;
{
register int16 ctl;
ulong realaddr;
unsigned page;
/* speed up access to 8530 regs */
ctl = dcbp->zhwmap.ctl;
/* if we are NOT DMA tx driven */
if(dcbp->dma_flg == FALSE)
{
/* reset CRC for next frame */
#ifdef TSYNC_DEBUG
Twin_write_scc(ctl,R0,(dcbp->wr0 = RES_Tx_CRC));
/* reset Tx int pending */
Twin_write_scc(ctl,R0,(dcbp->wr0 = 0x28));
#else
Twin_write_scc(ctl,R0,RES_Tx_CRC);
/* reset Tx int pending */
Twin_write_scc(ctl,R0,0x28);
#endif
/* Get First char to send */
/* send the transmission char and bump the pointer */
outportb(dcbp->zhwmap.data,*dcbp->cur_xbufp++);
dcbp->txstate = TX_ACTIVE;
/* sent one byte */
dcbp->cur_xbytes--;
#ifdef TSYNC_DEBUG
/* Rx/Tx and Extern ints on */
Twin_write_scc(ctl,R1,(dcbp->wr1 = 0x13));
/* Reset Underrun/EOM latch */
Twin_write_scc(ctl,R0,(dcbp->wr0 = 0xc0));
/* turn-on the xmission of Abort on underrun */
if(dcbp->nrzi_flg == TRUE)Twin_write_scc(ctl,R10,(dcbp->wr10 = 0xa4));
else Twin_write_scc(ctl,R10,(dcbp->wr10 = 0x84));
#else
/* Rx/Tx and Extern ints on */
Twin_write_scc(ctl,R1,0x13);
/* Reset Underrun/EOM latch */
Twin_write_scc(ctl,R0,0xc0);
/* turn-on the xmission of Abort on underrun */
if(dcbp->nrzi_flg == TRUE)Twin_write_scc(ctl,R10,0xa4);
else Twin_write_scc(ctl,R10,0x84);
#endif
/* 4/18/91 */
/* clear the TxEOM bit in the image */
dcbp->extreg &= ~TxEOM;
/* allow Underruns to interrupt us */
Twin_write_scc(ctl,R15,(dcbp->wr15 |= 0x40));
/* for slow PCs... mask out the timer ints... */
/* This will cause the pc to lose time during xmissions... */
/* but seems only way to make it work at 9600 */
if ((Twin_cputype < 2) && (dcbp->baud >= 9600L)) maskoff(0);
}
else
{
/* Reprime the tx dma pump... */
/* A rendition of an absolute address for ptr */
realaddr = ((ulong)FP_SEG(dcbp->cur_xbufp) << 4)
+ (ulong)FP_OFF(dcbp->cur_xbufp);
/* Disable this DMA channel */
outportb(DMAWSMR,dcbp->dma_tx_chan | 0x04);
/* DMA page reg for 8237 */
page = (unsigned)(realaddr >> 16);
/* setup 64k page */
outportb(dcbp->dma_tx_pagereg,page);
/* mode setup required if we are in HDX */
if(dcbp->hduplex == TRUE)
{
outportb(DMAMODE,dcbp->dma_tx_chan | TX_DMA);
outportb(Twin_io_base+DMA_CFG,dcbp->dma_tx_mode);
}
/* clear the DMA byte ptr FF */
outportb(DMAFFCL,00);
/* Max xfer count setup */
outportb(dcbp->dma_tx_cnt_reg,dcbp->cur_xbytes-1);
outportb(dcbp->dma_tx_cnt_reg,((dcbp->cur_xbytes-1)>>8));
/* destination buffer address */
outportb(dcbp->dma_tx_addr_reg,(realaddr & 0xff));
outportb(dcbp->dma_tx_addr_reg,((realaddr >> 8) & 0xff));
/* reset CRC for next frame */
#ifdef TSYNC_DEBUG
Twin_write_scc(ctl,R0,(dcbp->wr0 = RES_Tx_CRC));
#else
Twin_write_scc(ctl,R0,RES_Tx_CRC);
#endif
/* Enable this DMA channel */
outportb(DMAWSMR,dcbp->dma_tx_chan);
nop;
nop;
dcbp->txstate = TX_ACTIVE;
/* Reset Underrun/EOM latch */
#ifdef TSYNC_DEBUG
Twin_write_scc(ctl,R0,(dcbp->wr0 = 0xc0));
#else
Twin_write_scc(ctl,R0,0xc0);
#endif
/* allow Underruns to interrupt us */
Twin_write_scc(ctl,R15,(dcbp->wr15 |= 0x40));
/* clear the TxEOM bit in the image */
dcbp->extreg &= ~TxEOM;
#ifdef TSYNC_DEBUG
/* Rx and Extern ints on : No Tx ints */
Twin_write_scc(ctl,R1,(dcbp->wr1 = 0xf9));
/* reset Tx int pending */
Twin_write_scc(ctl,R0,(dcbp->wr0 = 0x28));
#else
/* Rx and Extern ints on : No Tx ints */
Twin_write_scc(ctl,R1,0xf9);
/* reset Tx int pending */
Twin_write_scc(ctl,R0,0x28);
#endif
}
}
/*
* Transmit and Receive Control
* SET Transmit or Receive Mode
* Set RTS (request-to-send) to modem on Transmit
*/
void
transon(dcbp, onoff)
register DCB *dcbp;
int16 onoff;
{
register int16 ctl;
/* speed-up access to the SCC's control register */
ctl = dcbp->zhwmap.ctl;
/* Turn on transmitter to send flags */
if ( onoff == ON )
{
/* If we are in DMA mode/Half duplex: Turn off the recvr */
/* Rx 8 bit/chars, enter hunt mode, CRC enable */
#ifdef notdef
/* NOT needed with autoenables */
Twin_write_scc(dcbp->zhwmap.ctl,R3,(dcbp->wr3 = 0xd8));
#endif
/* flags during KEYUP cause the other guy to sync up while */
/* he sees garbage*/
#ifdef TSYNC_DEBUG
if(dcbp->nrzi_flg == TRUE) Twin_write_scc(ctl,R10,(dcbp->wr10 = 0xa0));
else Twin_write_scc(ctl,R10,(dcbp->wr10 = 0x80));
/* Effectively just activate RTS */
/* Which is used to key the "radio transmitter" */
Twin_write_scc(dcbp->zhwmap.ctl,R5,(dcbp->wr5 = 0x6b));
#else
if(dcbp->nrzi_flg == TRUE) Twin_write_scc(ctl,R10,0xa0);
else Twin_write_scc(ctl,R10,0x80);
/* Effectively just activate RTS */
/* Which is used to key the "radio transmitter" */
Twin_write_scc(dcbp->zhwmap.ctl,R5,0x6b);
#endif
/*
* Transmitter now on
*/
/* Delay after Tx on */
/* Handle the special case of NO keyup delay... */
if(dcbp->ioctlparams->xmitdelay == 0)tsync_txondelay(dcbp);
/* otherwise set up the keyup timer... */
else
time_wait(dcbp,dcbp->timer1, dcbp->ioctlparams->xmitdelay, tsync_txondelay,(long)dcbp);
}
else
{ /* Tx OFF and Rx ON */
/* delay for squelch tail before enable of Rx */
/* Handle the special case of NO keydown delay... */
if(dcbp->ioctlparams->squelch == 0)tsync_sqdelay(dcbp);
/* otherwise set up the keydown timer... */
else
time_wait(dcbp,dcbp->timer1, dcbp->ioctlparams->squelch, tsync_sqdelay,(long)dcbp);
}
return;
}
/*
* end of transon
********************************************************************/
/*
* Called by the timer isr at an interrupt level.
* Persist time is up.
*/
void tsync_persist(dcbp)
DCB *dcbp;
{
/* new for NOS */
/* persist time is up, have NOS process check for transmit */
/* by changing the driver's transmit state */
dcbp->txstate = DEFER;
/* AND signal the process which is supposed to kick */
/* the transmitter */
psignal(&Twin_kickpp[dcbp->dev],1);
return;
}
/*
* Called by the timer isr at an interrupt level.
* Transmitter on delay is up.
*/
void tsync_txondelay(dcbp)
DCB *dcbp;
{
/* transmiter is ON and can start sending */
dcbp->txstate = KEYED_UP;
tsync_txisr(dcbp);
return;
}
/*
* Called by the timer isr at an interrupt level.
* Squelch delay is up.
*/
void tsync_sqdelay(dcbp)
DCB *dcbp;
{
register int16 ctl;
/* We are going to shut down the "radio" transmitter. */
/* REGARDLESS of whether we now have a new frame to send */
/* or not... Because if we DO have more to send, we */
/* set txstate to DEFER, and let the tsync_recv routine */
/* kick us off again from the start, and if we don't */
/* have more to send we go to IDLE mode. */
/* speed-up access to the SCC's control register */
ctl = dcbp->zhwmap.ctl;
/* Send MARK on IDLE to make sure other guy aborts any trailing */
/* garbage */
/* EXCEPT in NRZI... */
#ifdef TSYNC_DEBUG
if(dcbp->nrzi_flg == TRUE) Twin_write_scc(ctl,R10,(dcbp->wr10 = 0xa0));
else Twin_write_scc(ctl,R10,(dcbp->wr10 = 0x88));
Twin_write_scc(ctl,R5,(dcbp->wr5 = 0x68)); /* TX off now */
/* I.E. drop RTS */
#else
if(dcbp->nrzi_flg == TRUE) Twin_write_scc(ctl,R10,0xa0);
else Twin_write_scc(ctl,R10,0x88);
Twin_write_scc(ctl,R5,0x68); /* TX off now */
/* I.E. drop RTS */
#endif
/* re-prime the dma driver if necessary */
/* Necessary because we took the SINGLE dma channel away */
/* and used it to transmit... now give it back to receiver */
if((dcbp->dma_flg == TRUE) && (dcbp->hduplex == TRUE))rxprime_dma(dcbp);
/* perhaps while waiting for the squelch delay tsync_raw was */
/* called and there is a buffer to send */
if ( dcbp->xmtq != (struct drvbuf *)NULLBUF )
{ /* then start the transmit process */
/* but not at an interrupt level!! */
/* now when tsync_recv is called, tx_isr will run */
dcbp->cur_xbufp = &(dcbp->xmtq->buf);
dcbp->cur_xbytes = dcbp->xmtq->msgsize;
/* new for NOS */
/* signal the process which is supposed to kick */
/* the transmitter */
dcbp->txstate = DEFER;
psignal(&Twin_kickpp[dcbp->dev],1);
}
else
{ /* now only when tsync_raw runs will the transmit */
/* process go on */
dcbp->txstate = IDLE;
}
return;
}
/* This is the driver timer service. */
/* It's resolution is in 1 msec intervals */
void
time_wait(dcbp,timer,msecs,timerfunc,arg)
DCB *dcbp;
struct drv_timer *timer;
int16 msecs;
void (*timerfunc)();
unsigned long arg;
{
int16 hrd_addr;
/* calculate the timer counter reg address */
hrd_addr = Twin_io_base + TMR_CNT1 + dcbp->dev;
timer->thandler = timerfunc;
timer->targ = arg;
/* start the timer */
outportb(hrd_addr,(uchar)(msecs & 0xff));
nop;
nop;
outportb(hrd_addr,(uchar)(msecs >> 8));
nop;
nop;
}
/***********************************************************
* GRACILIS - processes to manage buffer maintenance for the
* PackeTwin synchronous drivers. These processes
* are used to insure that buffer maintenance is
* not performed at interrupt time.
***********************************************************/
/* This process is used to pre-allocate receive */
/* buffers for the 8530 synchronous driver to use. */
void
tsync_rxavget(dev, p1, p2)
int dev; /* device number */
void *p1; /* not used */
void *p2; /* not used */
{
register int i_state;
DCB *dcbp;
int16 cur_rxavail, min_rxavail;
/* killself if device is not attached yet */
if (dev > 1) /* only support 0 through 1 */
return;
else if (Twin_udcb[dev].attached == FALSE)
return;
for (;;)
{
/* wait for the driver to signal it needs */
/* a look at its pre-allocated receive buffers */
pwait(&Twin_bufpp[dev]);
dcbp = (DCB *)Twin_udcb[dev].dcbp;
i_state = dirps();
cur_rxavail = dcbp->rxavailcount;
min_rxavail = dcbp->ioctlparams->rxavailbufs;
restore(i_state);
/* see if more receive buffers need allocating */
if ( cur_rxavail < min_rxavail )
{
f_getavail((struct mbuf **)&(dcbp->rxavailq),
(int16)(min_rxavail - cur_rxavail),
(int16)dcbp->rxbufsize,
(int16 *)&(dcbp->rxavailcount),
(struct iface *)dcbp->iface,
(bool)dcbp->dma_flg);
}
} /* end of for(;;) loop */
} /* end of tsync_rxavget() */
/* This process is used to periodically kick */
/* the PackeTwin synchronous driver whenever */
/* it is in the DEFERED state */
void
tsync_txkick(dev, p1, p2)
int dev; /* device number */
void *p1; /* not used */
void *p2; /* not used */
{
register DCB *dcbp;
register bool pwait_null = FALSE; /* 1st time wait for driver's psignal */
void tsync_txisr();
/* killself if device is not attached yet */
if (dev > 1) /* only support 0 through 1 */
return;
else if (Twin_udcb[dev].attached == FALSE)
return;
for (;;)
{
/* wait for the driver to signal it needs */
/* kick */
if ( pwait_null )
pwait(NULL); /* have NOS provide */
/* the delay needed */
else
pwait(&Twin_kickpp[dev]);
/* driver control block */
dcbp = (DCB *)Twin_udcb[dev].dcbp;
/* Test for DEFERED transmit state */
if (dcbp->txstate == DEFER)
{
tsync_txisr(dcbp);
if ( dcbp->txstate == DEFER )
pwait_null = TRUE; /* then driver still */
/* needs a kick */
else
pwait_null = FALSE;
}
} /* end of for(;;) loop */
} /* end of tsync_txkick() */
/* This process is used to free buffers */
/* which have been transmitted by the driver. */
void
tsync_freetx(dev, p1, p2)
int dev; /* device number */
void *p1; /* not used */
void *p2; /* not used */
{
register int i_state;
register DCB *dcbp;
register struct drvbuf *xbufp, *btemp;
/* killself if device is not attached yet */
if (dev > 4) /* only support 0 through 4 */
return;
else if (Twin_udcb[dev].attached == FALSE)
return;
for (;;)
{
/* wait for driver to signal that there are transmitted */
/* messages to be freed */
pwait(&Twin_freetxpp[dev]);
/* driver control block */
dcbp = (DCB *)Twin_udcb[dev].dcbp;
/* Do not do memory free-ups while interrupts are */
/* disabled! Here xbufp is a "to be free'd" */
/* queue pointer" */
i_state = dirps();
xbufp = dcbp->freem;
dcbp->freem = NULLBUF;
restore(i_state);
/* now free memory of all the xmitted messages */
while ( xbufp != (struct drvbuf *)NULL )
{
btemp = xbufp->next;
free((char *)xbufp);
xbufp = btemp;
}
} /* end of for(;;) loop */
} /* end of tsync_freetx() */
#endif